use chrono::Local;
use sqlite_wasm_rs::sqlite3_stmt;
use crate::db::db::{Db, DbParamType};
use crate::db::pojo::pojo::{ImUser};
use crate::db::util::{db_get_int, db_get_int64, db_get_string};
use crate::util::time::parse_to_time;

pub fn user_inserts(db: Db, users: Vec<&mut ImUser>) {
    if users.is_empty() {
        return;
    }
    log::info!("users inserts: {:?}", users);
    let sql = c"insert into im_user(userId, userName, mobile, motto, description, headImg, status, sex, departmentCode,
        otherDepartmentCodes, ext1, ext2, firstLetter, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    let mut params = vec![];

    for user in users {
        let mut param = Vec::new();
        param.push(DbParamType::Str(&*user.user_id));
        param.push(DbParamType::Str(&*user.user_name));
        param.push(DbParamType::OptionStr(user.mobile.as_ref()));
        param.push(DbParamType::OptionStr(user.motto.as_ref()));
        param.push(DbParamType::OptionStr(user.description.as_ref()));
        param.push(DbParamType::OptionStr(user.head_img.as_ref()));
        param.push(DbParamType::Int(user.status.clone() as i64));
        param.push(DbParamType::Int(user.sex.clone() as i64));
        param.push(DbParamType::OptionStr(user.department_code.as_ref()));
        param.push(DbParamType::OptionStr(user.other_department_codes.as_ref()));
        param.push(DbParamType::OptionStr(user.ext1.as_ref()));
        param.push(DbParamType::OptionStr(user.ext2.as_ref()));
        param.push(DbParamType::OptionStr(user.first_letter.as_ref()));
        param.push(DbParamType::DateTime2(&user.create_date_time));
        param.push(DbParamType::DateTime2(&user.update_date_time));
        params.push(param);
    }
    log::info!("db inserts user params: {:?}", params);
    db.inserts("user inset", sql, params);
}

pub fn user_updates(db: Db, users: Vec<&mut ImUser>) {
    if users.is_empty() {
        return;
    }
    log::info!("db user update: {:?}", users);

    let sql = "update im_user set mobile = ?, motto = ?, description = ?, headImg = ?, status = ?, departmentCode = ?,
        otherDepartmentCodes = ?, ext1 = ?, ext2 = ?, firstLetter = ?, updateTime = ? where userId = ?";
    let mut params = vec![];
    for user in users {
        let mut param = Vec::new();

        param.push(DbParamType::OptionStr(user.mobile.as_ref()));
        param.push(DbParamType::OptionStr(user.motto.as_ref()));
        param.push(DbParamType::OptionStr(user.description.as_ref()));
        param.push(DbParamType::Int(user.status.clone() as i64));
        param.push(DbParamType::OptionStr(user.department_code.as_ref()));
        param.push(DbParamType::OptionStr(user.other_department_codes.as_ref()));
        param.push(DbParamType::OptionStr(user.ext1.as_ref()));
        param.push(DbParamType::OptionStr(user.ext2.as_ref()));
        param.push(DbParamType::OptionStr(user.first_letter.as_ref()));
        param.push(DbParamType::DateTime(Local::now()));
        // param.push(DbParamType::Str(&*department.current_user_id));
        param.push(DbParamType::Str(&*user.user_id));
        params.push(param);
    }
    log::info!("db user update params: {:?}", params);
    db.batch_exec("user updates", sql.to_string(), params);
}

pub fn query_users_by_user_ids(db: Db, user_ids: Vec<String>) -> Vec<ImUser> {
    if user_ids.is_empty() { return Vec::new(); }
    let sql_where = user_ids.iter().map(|_code| "?").collect::<Vec<&str>>().join(",");
    let sql = format!("SELECT id, userId, userName, mobile, motto, description, headImg, status, sex, departmentCode,
        otherDepartmentCodes, ext1, ext2, firstLetter, createTime, updateTime FROM im_user where userId in ({})", sql_where);
    let mut params = vec![];
    user_ids.into_iter().for_each(|user_id| {
        params.push(DbParamType::String(user_id));
    });
    db.query2("user query", sql.as_str(), params, Box::new(user_wrap))
}

pub fn query_user_by_user_id(db: Db, user_id: &str) -> Option<ImUser> {
    let sql = "SELECT id, userId, userName, mobile, motto, description, headImg, status, sex, departmentCode,
        otherDepartmentCodes, ext1, ext2, firstLetter, createTime, updateTime FROM im_user where userId = ?";
    let mut params = vec![];
    params.push(DbParamType::Str(user_id));
    db.query_one("user query2", sql.to_string(), params, Box::new(user_wrap))
}

pub fn user_total(db: Db)-> usize {
    let size = db.count("user total", c"select count(*) from im_user", Vec::new());
    log::info!("db user count: {}", size);
    size
}

fn user_wrap(stmt: *mut sqlite3_stmt) -> ImUser {
    unsafe  {
        let id = db_get_int64(stmt, 0);
        let user_id = db_get_string(stmt, 1).unwrap();
        let user_name = db_get_string(stmt, 2).unwrap();
        let mobile = db_get_string(stmt, 3);
        let motto = db_get_string(stmt, 4);
        let description = db_get_string(stmt, 5);
        let head_img = db_get_string(stmt, 6);
        let status = db_get_int(stmt, 7);
        let sex = db_get_int(stmt, 8);
        let department_code = db_get_string(stmt, 9);
        let other_department_codes = db_get_string(stmt, 10);
        let ext1 = db_get_string(stmt, 11);
        let ext2 = db_get_string(stmt, 12);
        let first_letter = db_get_string(stmt, 13);
        let create_time_str = db_get_string(stmt, 14).unwrap();
        let update_time_str = db_get_string(stmt, 15).unwrap();

        let status2 = serde_json::from_str(status.to_string().as_str()).unwrap();
        let sex2 = serde_json::from_str(sex.to_string().as_str()).unwrap();
        ImUser {
            id: Some(id),
            user_id,
            user_name,
            mobile,
            motto,
            head_img,
            description,
            department_code,
            other_department_codes,
            status: status2,
            sex: sex2,
            ext1,
            ext2,
            first_letter,
            create_date_time: parse_to_time(create_time_str),
            update_date_time: parse_to_time(update_time_str),
        }
    }

}